﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Xml;
using System.Collections.Specialized;
using Meraz.Core.Model;

namespace Meraz.Core.Parsers
{
    public abstract class BlogParserBase : IBlogParser
    {
        protected const string linkPattern = @"<a.*?href=(?<href>.*?)(?((?:\s.*?)>.*?</a>)(?:(?:\s.*?)>(.*?)</a>)|(?:>(.*?)</a>))";
        protected const string embedPattern = @"(?<=<embed\s[^<>]*?src\s*?=\s*?\x22)[^<>]*?(?=\x22[^<>]*?>)";
        public abstract PostValues Parse(string permalink, string source);
        
        public BlogKeyType BlogKey { get; set; }
        public List<string> LinksToIgnoreList { get; set; }
        Dictionary<string, string> Encodings = new Dictionary<string, string>();
        Dictionary<string, int> Months = new Dictionary<string, int>();


        #region Field: static string[][] TimeZones
        private static string[][] TimeZones = new string[][] {
    new string[] {"ACDT", "+1030", "Australian Central Daylight"},
    new string[] {"ACST", "+0930", "Australian Central Standard"},
    new string[] {"ADT", "-0300", "(US) Atlantic Daylight"},
    new string[] {"AEDT", "+1100", "Australian East Daylight"},
    new string[] {"AEST", "+1000", "Australian East Standard"},
    new string[] {"AHDT", "-0900", ""},
    new string[] {"AHST", "-1000", ""},
    new string[] {"AST", "-0400", "(US) Atlantic Standard"},
    new string[] {"AT", "-0200", "Azores"},
    new string[] {"AWDT", "+0900", "Australian West Daylight"},
    new string[] {"AWST", "+0800", "Australian West Standard"},
    new string[] {"BAT", "+0300", "Bhagdad"},
    new string[] {"BDST", "+0200", "British Double Summer"},
    new string[] {"BET", "-1100", "Bering Standard"},
    new string[] {"BST", "-0300", "Brazil Standard"},
    new string[] {"BT", "+0300", "Baghdad"},
    new string[] {"BZT2", "-0300", "Brazil Zone 2"},
    new string[] {"CADT", "+1030", "Central Australian Daylight"},
    new string[] {"CAST", "+0930", "Central Australian Standard"},
    new string[] {"CAT", "-1000", "Central Alaska"},
    new string[] {"CCT", "+0800", "China Coast"},
    new string[] {"CDT", "-0500", "(US) Central Daylight"},
    new string[] {"CED", "+0200", "Central European Daylight"},
    new string[] {"CET", "+0100", "Central European"},
    new string[] {"CST", "-0600", "(US) Central Standard"},
    new string[] {"CENTRAL", "-0600", "(US) Central Standard"},
    new string[] {"EAST", "+1000", "Eastern Australian Standard"},
    new string[] {"EDT", "-0400", "(US) Eastern Daylight"},
    new string[] {"EED", "+0300", "Eastern European Daylight"},
    new string[] {"EET", "+0200", "Eastern Europe"},
    new string[] {"EEST", "+0300", "Eastern Europe Summer"},
    new string[] {"EST", "-0500", "(US) Eastern Standard"},
    new string[] {"EASTERN", "-0500", "(US) Eastern Standard"},
    new string[] {"FST", "+0200", "French Summer"},
    new string[] {"FWT", "+0100", "French Winter"},
    new string[] {"GMT", "-0000", "Greenwich Mean"},
    new string[] {"GST", "+1000", "Guam Standard"},
    new string[] {"HDT", "-0900", "Hawaii Daylight"},
    new string[] {"HST", "-1000", "Hawaii Standard"},
    new string[] {"IDLE", "+1200", "Internation Date Line East"},
    new string[] {"IDLW", "-1200", "Internation Date Line West"},
    new string[] {"IST", "+0530", "Indian Standard"},
    new string[] {"IT", "+0330", "Iran"},
    new string[] {"JST", "+0900", "Japan Standard"},
    new string[] {"JT", "+0700", "Java"},
    new string[] {"MDT", "-0600", "(US) Mountain Daylight"},
    new string[] {"MED", "+0200", "Middle European Daylight"},
    new string[] {"MET", "+0100", "Middle European"},
    new string[] {"MEST", "+0200", "Middle European Summer"},
    new string[] {"MEWT", "+0100", "Middle European Winter"},
    new string[] {"MST", "-0700", "(US) Mountain Standard"},
    new string[] {"MOUNTAIN", "-0700", "(US) Mountain Standard"},
    new string[] {"MT", "+0800", "Moluccas"},
    new string[] {"NDT", "-0230", "Newfoundland Daylight"},
    new string[] {"NFT", "-0330", "Newfoundland"},
    new string[] {"NT", "-1100", "Nome"},
    new string[] {"NST", "+0630", "North Sumatra"},
    new string[] {"NZ", "+1100", "New Zealand "},
    new string[] {"NZST", "+1200", "New Zealand Standard"},
    new string[] {"NZDT", "+1300", "New Zealand Daylight "},
    new string[] {"NZT", "+1200", "New Zealand"},
    new string[] {"PDT", "-0700", "(US) Pacific Daylight"},
    new string[] {"PST", "-0800", "(US) Pacific Standard"},
    new string[] {"PACIFIC", "-0800", "(US) Pacific Standard"},
    new string[] {"ROK", "+0900", "Republic of Korea"},
    new string[] {"SAD", "+1000", "South Australia Daylight"},
    new string[] {"SAST", "+0900", "South Australia Standard"},
    new string[] {"SAT", "+0900", "South Australia Standard"},
    new string[] {"SDT", "+1000", "South Australia Daylight"},
    new string[] {"SST", "+0200", "Swedish Summer"},
    new string[] {"SWT", "+0100", "Swedish Winter"},
    new string[] {"USZ3", "+0400", "USSR Zone 3"},
    new string[] {"USZ4", "+0500", "USSR Zone 4"},
    new string[] {"USZ5", "+0600", "USSR Zone 5"},
    new string[] {"USZ6", "+0700", "USSR Zone 6"},
    new string[] {"UT", "-0000", "Universal Coordinated"},
    new string[] {"UTC", "-0000", "Universal Coordinated"},
    new string[] {"UZ10", "+1100", "USSR Zone 10"},
    new string[] {"WAT", "-0100", "West Africa"},
    new string[] {"WET", "-0000", "West European"},
    new string[] {"WST", "+0800", "West Australian Standard"},
    new string[] {"YDT", "-0800", "Yukon Daylight"},
    new string[] {"YST", "-0900", "Yukon Standard"},
    new string[] {"ZP4", "+0400", "USSR Zone 3"},
    new string[] {"ZP5", "+0500", "USSR Zone 4"},
    new string[] {"ZP6", "+0600", "USSR Zone 5"}
};
        #endregion


        public BlogParserBase(){
            Encodings.Add("&#8217;", "'");

            Months.Add("Jan", 1);
            Months.Add("Feb", 2);
            Months.Add("Mar", 3);
            Months.Add("Apr", 4);
            Months.Add("May", 5);
            Months.Add("Jun", 6);
            Months.Add("Jul", 7);
            Months.Add("Aug", 8);
            Months.Add("Sep", 9);
            Months.Add("Oct", 10);
            Months.Add("Nov", 11);
            Months.Add("Dec", 12);

            Months.Add("January", 1);
            Months.Add("February", 2);
            Months.Add("March", 3);
            Months.Add("April", 4);
            Months.Add("June", 6);
            Months.Add("July", 7);
            Months.Add("August", 8);
            Months.Add("September", 9);
            Months.Add("October", 10);
            Months.Add("November", 11);
            Months.Add("December", 12);
        }

        protected DateTime NewDateTime(string year, string month, string day, string hour, string minute, string time)
        {
            int yr = int.Parse(year);
            int mon = (Months.ContainsKey(month)) ? Months[month] : int.Parse(month);
            int dy = int.Parse(day);
            int hr = int.Parse(hour);
            int min = int.Parse(minute);
            if (time == "pm")
                hr += 12;
            return new DateTime(yr, mon, dy, hr, min, 0);
        }
        protected DateTime NewDateTime(string year, string month, string day, string hour, string minute)
        {
            int yr = int.Parse(year);
            int mon = (Months.ContainsKey(month)) ? Months[month] : int.Parse(month);
            int dy = int.Parse(day);
            int hr = int.Parse(hour);
            int min = int.Parse(minute);
            return new DateTime(yr, mon, dy, hr, min, 0);
        }
        protected int GetMonth(string month)
        {
            return (Months.ContainsKey(month)) ? Months[month] : int.Parse(month);
        }
        protected string GetTimeZoneOffset(string timeZoneAbbreviation)
        {
            string[] zone = TimeZones.Where(where1 => where1.ElementAt(0).Equals(timeZoneAbbreviation)).FirstOrDefault();
            if (zone == null) 
                zone = TimeZones.Where(where1 => where1.ElementAt(0).Equals("EST")).FirstOrDefault();
            return zone[1];
        }
        public List<string> ParseLinks(string body)
        {
            List<string> hrefs = new List<string>();
            LinkParser linkParser = new LinkParser();
            List<string[]> links = linkParser.Parse(body);
            foreach (string[] linkPair in links)
            {

                string href = linkPair[0];
                if (!hrefs.Contains(href))
                {
                    Uri uri = new Uri(href);
                    if (uri.IsAbsoluteUri)
                        hrefs.Add(href);
                }
            }
            return hrefs;
        }

        protected string GetTitle(string source)
        {
            Regex regex = new Regex(@"<title>(?<title>[^<]*)</title>", RegexOptions.IgnoreCase | RegexOptions.Multiline);
            Match match = regex.Match(source);
            string title = string.Empty;
            if (match.Success)
            {
                title = CollapseWhitespace(match.Groups["title"].Value);
            }
            return title.Trim();
        }
        protected string RemoveHtml(string value)
        {
            Regex regex = new Regex("<[^>]*>");
            return regex.Replace(value, "").Trim();
        }
        protected string CollapseWhitespace(string value)
        {
            if (string.IsNullOrWhiteSpace(value))
                return string.Empty;
            string results = value.Trim();
            Regex regex = new Regex(@"[\s]+");
            return regex.Replace(value, " ");
        }
    }
    public class GenericParser : BlogParserBase
    {
        public GenericParser() : this(BlogKeyType.Unknown) { }
        public GenericParser(BlogKeyType blogKey) { this.BlogKey = blogKey; }
        public override PostValues Parse(string permalink, string source)
        {
            if (string.IsNullOrWhiteSpace(source))
                return null;
            PostValues post = new PostValues();
            //use domain name
            post.Permalink = permalink;
            post.BlogName = this.BlogKey.ToString();
            post.Title = GetTitle(source);
            int start, end;
            start = source.IndexOf("<body");
            start = source.IndexOf(">", start) + 1;
            end = source.LastIndexOf("</body>");
            post.Body = source.Substring(start, end - start);
            return post;
        }
    }
    

}
